/*
 * PhotonRTOS础光实时操作系统 -- object
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Jiayuan Liang <liangjiayuan@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <autosar/internal.h>
#include <photon/sched.h>

#if defined(AUTOSAR_OS_APPLICATION)
/**
 * 服务名字
 *      AllowAccess
 * 语法
 *	StatusType AllowAccess (void)
 * 服务 ID [hex]
 *	0x13
 * 同步/异步
 *	同步（Synchronous）
 * 可重入性
 *	可重入
 * 参数 (in)
 *	None
 * 参数 (inout)
 *	None
 * 参数 (out)
 *	None
 * 返回值
 *      StatusType
 *		E_OK：没有错误
 *		E_OS_STATE：调用者的OS-Application处于错误状态
 * 描述
 *	该服务将 OS-Application 的自身状态从 APPLICATION_RESTARTING 设置为
 *  APPLICATION_ACCESSIBLE。
 * 引用
 *	AUTOSAR OS 8.4.21 AllowAccess [SWS_Os_00501]
 */
FUNC(StatusType, OS_CODE) AllowAccess(void)
{
	VAR(ApplicationType, AUTOMATIC) caller_app_id = current_proc_info()->object.app_id;
	VAR(StatusType, AUTOMATIC) ret = E_OK;

	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR)

#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00497] 如果调用者的app_id不是APPLICATION_RESTARTING，那么返回E_OS_STATE
	*/
	if (autosar_os_app[caller_app_id].state != APPLICATION_RESTARTING) {
		ret = E_OS_STATE;
		goto out;
	}
#endif

	ret = autosar_allow_access();
out:
	return ret;
}
#endif /* defined(AUTOSAR_OS_APPLICATION) */

#if defined(AUTOSAR_TRUSTED_FUNCTION)
/**
 * [SWS_Os_00312] ⌈ CallTrustedFunction()的注意事项：
 * 被调用的可信函数必须符合以下 C 原型： void TRUSTED_<name_of_the_trusted_service>( TrustedFunctionIndexType , TrustedFunctionParameterRefType);
 * （参数与 CallTrustedFunction 的参数相同）。
 * 通常，用户不会直接调用此服务，但它会是一些标准接口的一部分，例如标准 I/O 接口。
 * 被调用的受信任函数的职责是检查传递参数的权限，尤其是当参数被解释为输出参数时。
 * 需要注意的是， CallTrustedFunction()不会为调用该服务的任务禁用定时保护。即使在受信任的操作系统应用程序内部，这也可能导致计时错误（调用ProtectionHook() ）。因此建议仅将CallTrustedFunction()用于无状态函数（例如，不写入或没有内部状态的函数） ⌋ ( )
 */

/**
 * [SWS_Os_00364] ⌈如果CallTrustedFunction( )从 2 类 ISR 上下文调用可信函数，该函数应继续以相同的中断优先级运行，并允许调用为 2 类 ISR 定义的所有系统服务（参见第 7.7.3.2 章中的表）。 ⌋ ( )
 * [SWS_Os_00365] ⌈如果CallTrustedFunction( )从任务上下文调用可信函数，该函数应继续以相同的优先级运行，并允许调用为任务定义的所有系统服务（参见第 7.7.3.2 章中的表）。 ⌋ ( )
 */

/**
 * [SWS_OS_00516] CallTrustedFunction()的可用性：在可扩展性等级 3 和 4 中可用。⌋ ( )
 */
FUNC(StatusType, OS_CODE) CallTrustedFunction(
	VAR(TrustedFunctionIndexType, AUTOMATIC) FunctionIndex,
	VAR(TrustedFunctionParameterRefType, AUTOMATIC) FunctionParams)
{
	VAR(int32_t, AUTOMATIC) max_prio = -1;
	VAR(int32_t, AUTOMATIC) tmp_prio = current->sched_prio;
	VAR(StatusType, AUTOMATIC) status = E_OK;
	VAR(ApplicationType, AUTOMATIC) caller_app_id;
	VAR(ApplicationType, AUTOMATIC) func_app_id;
	P2VAR(struct process_desc, AUTOMATIC, OS_APPL_DATA) pro_desc;
	P2VAR(struct process_desc, AUTOMATIC, OS_APPL_DATA) tmp_pro_desc;
	VAR(int32_t, AUTOMATIC) i;

	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR)

	pro_desc = current_proc_info();
	/**
	 * [SWS_Os_00565]  ⌈当 CallTrustedFunction() 被调用并且 CallTrustedFunction() 的调用者受到时序保护的监督时，操作系统将延迟任何时序保护错误，直到 CallTrustedFunction() 返回到 OsApplication 且OsTrustedApplicationDelayTimingViolationCall == FALSE。⌋ ( )
	 * [SWS_Os_00564] ⌈如果在任务的 CallTrustedFunction() 的嵌套调用序列中检测到此类违规，则延迟将持续到 CallTrustedFunction() 返回	到 OsApplication 且OsTrustedApplicationDelayTimingViolationCall == FALSE 。 ⌋ ( )
	 */
	time_protect_disable = 1;
	func_app_id = autosar_trusted_func[FunctionIndex].app_id;
	caller_app_id = GetApplicationID();

	pro_desc->object.trusted_func_app_id = func_app_id;

#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00100] 如果FunctionIndex所指向的function不合法，那么应该以E_OS_SERVICEID为参数，调用ErrorHook.
	 * [SWS_Os_00623] CallTrustedFunction 调用的 function 所属的os-app应该和caller所属
	 * 的os-app位于同一个核上
	 * [SWS_Os_00292] ⌈如果CallTrustedFunction( )调用中的函数索引 <FunctionIndex>未定
	 * 义，则 CallTrustedFunction()应返回E_OS_SERVICEID 。 ⌋ ( )
	 */
	if (FunctionIndex >= MAX_TRUSTED_FUNC_NUM ||
		autosar_trusted_func[FunctionIndex].trusted_func == NULL
		|| GetCoreID() != autosar_os_app[func_app_id].core_id ||
		autosar_trusted_func[FunctionIndex].accessable_application_id[caller_app_id] != 1) {
		status = E_OS_SERVICEID;
		goto out;
	}
#endif

	/**
	 * [SWS_Os_00563]  ⌈操作系统不应调度与服务的非信任调用者属于同一 OS-Application 的任何其他任务。应按优先级上限进行。属于同一 OSApplication 的第 2 类中断也应在服务执行期间禁用。 ⌋ ( )
	 * [ SWS_Os_00266 ] 如果任务在 CallTrustedFunction() 内部，并且任务重新调度发
	 * 生在同一个 OSApplication 中，则新运行的更高优先级任务可能会导致时序
	 * 保护并终止 OSApplication，从而间接中止可信函数。为了避免这种情况，
	 * 需要限制与调用者属于同一 OS-Application 的其他 Task 的调度，以及同一
	 *  OS-Application 的中断的可用性
	 */
	for (i = 0; i <OS_NR_TASK; i++) {
		if (osek_tasks[i].stack == NULL) {
			continue;
		}
		tmp_pro_desc = osek_tasks[i].stack;
		if (tmp_pro_desc->object.app_id == func_app_id &&
			osek_tasks[i].sched_prio > max_prio) {
			max_prio = osek_tasks[i].sched_prio;
		}
	}
	osek_task_change_prio(osek_current_id(), max_prio + 1);

	/**
	 * [SWS_Os_00265] ⌈ 如果 <FunctionIndex> 是一个定义的函数索引， CallTrustedFunction()将调用函数 <FunctionIndex> 从实现特定可信函数列表中使用提供可信函数的 OSApplication 的保护设置，并在完成后返回E_OK 。 ⌋ ( )
	 */
	autosar_call_trusted_function(FunctionIndex, FunctionParams);
	pro_desc->object.trusted_func_app_id = INVALID_OSAPPLICATION;
out:
	if (status != E_OK) {
		osek_call_hook_0(CallTrustedFunction, status);
	}
	/**
	 * 恢复任务在调用CallTrustedFunction()之前的优先级。
	*/
	osek_task_change_prio(osek_current_id(), tmp_prio);
	time_protect_disable = 0;

	return status;
}
#endif /* defined(AUTOSAR_TRUSTED_FUNCTION) */

#if defined(AUTOSAR_OS_APPLICATION)
FUNC(ObjectAccessType, OS_CODE) CheckObjectAccess(
	VAR(ApplicationType, AUTOMATIC) ApplID,
	VAR(ObjectTypeType, AUTOMATIC) ObjectType,
	P2VAR(void, AUTOMATIC, OS_APPL_DATA) object)
{
	VAR(ObjectAccessType, AUTOMATIC) status = ACCESS;

#if defined(EXTENDED_STATUS)
	VAR(OsObjectRefType, AUTOMATIC) obj = (OsObjectRefType) object;
#endif
	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR | ENV_ERROR_HOOK | ENV_PROTECTION_HOOK)
#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00423] 如果object不是一个有效对象，或者ApplID不合法,或者ObjectType不合法， 则返回NO_ACCESS;
	*/
	if (obj == NULL || obj->object_type != ObjectType ||
		ApplID >= AUTOSAR_NR_APPLICATION) {
		status = NO_ACCESS;
		goto out;
	}
#endif
	status = autosar_check_object_access(ApplID, ObjectType, object);
out:
	return status;
}
#endif /* defined(AUTOSAR_OS_APPLICATION) */

#if defined(AUTOSAR_OS_APPLICATION)
FUNC(ApplicationType, OS_CODE) CheckObjectOwnership(
	VAR(ObjectTypeType, AUTOMATIC) ObjectType,
	P2VAR(void, AUTOMATIC, OS_APPL_DATA) object)
{
	VAR(OsObjectRefType, AUTOMATIC) obj = (OsObjectRefType) object;
	VAR(ApplicationType, AUTOMATIC) app_id;

	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR | ENV_ERROR_HOOK | ENV_PROTECTION_HOOK)

#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00274] 如果object不符合条件，或者obj不属于任何os-app，则返回 INVALID_OSAPPLICATION
	*/
	if (obj == NULL || obj->object_type != ObjectType ||
		!(obj->app_id < INVALID_OSAPPLICATION)) {
		app_id = INVALID_OSAPPLICATION;
		goto out;
	}
#endif

	app_id = autosar_check_object_ownership(ObjectType, object);
out:
	return app_id;
}
#endif /* defined(AUTOSAR_OS_APPLICATION) */
